﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CustomSerializer.Tests
{
    public class SimpleTypesChild : SimpleTypes, IComparable
    {
        public int childInt;
        public string childString;
        public Guid childGuid;
        public object childObject;

        public SimpleTypesChild() { }

        public SimpleTypesChild(bool init):base(init) {
            if (!init) return;

            Random r = new Random((int)(DateTime.Now.Ticks % int.MaxValue));
            childInt = r.Next(int.MaxValue);
            childString = r.Next(int.MaxValue) + " ...  " + r.Next(int.MaxValue);
            childGuid = new Guid(Enumerable.Range(0, 16).Select(p => (byte) ((r.Next(255)*p) & 0xFF)).ToArray());
            childObject = new Tuple<int, string, Guid>(
                r.Next(int.MaxValue),
                r.Next(int.MaxValue).ToString(),
                new Guid(Enumerable.Range(0, 16).Select(p => (byte) ((r.Next(255)*p) & 0xFF)).ToArray()));
        }

        int IComparable.CompareTo(object o)
        {
            var r = (SimpleTypesChild) o;
            return base.CompareTo(o) == 0
                   && childInt == r.childInt
                   && string.Compare(childString, r.childString, false) == 0
                   && Guid.CompareTo(r.childGuid) == 0
                ? 0
                : 1;
        }
    }

    public class MixedBaseChild:IComparable
    {
        public SimpleTypesChild Child;
        public SimpleTypes Base;
        public SimpleTypes ChildInBaseField;

        public List<SimpleTypesChild> ChildList;
        public List<SimpleTypes> BaseList;
        public List<SimpleTypes> ChildInBaseList;
        public List<object> MixedList;

        public SimpleTypesChild[] ChildArray;
        public SimpleTypes[] BaseArray;
        public SimpleTypes[] ChildInBaseArray;
        public object[] MixedArray;

        public Dictionary<string, SimpleTypesChild> ChildDict;
        public Dictionary<Guid, SimpleTypes> BaseDict;
        public Dictionary<int, SimpleTypes> ChildInBaseDict;
        public Dictionary<string, object> MixedDict;

        public MixedBaseChild() { }

        public MixedBaseChild(bool init)
        {
            if (!init) return;

            Random r = new Random((int)(DateTime.Now.Ticks % int.MaxValue));
            Child = new SimpleTypesChild(init);
            Base = new SimpleTypes(init);
            ChildInBaseField = new SimpleTypesChild(init);

            #region list
            ChildList = new List<SimpleTypesChild>() {
                new SimpleTypesChild(init),
                null,
                new SimpleTypesChild(false),
                null
            };

            BaseList = new List<SimpleTypes>() {
                new SimpleTypes(init),
                null,
                new SimpleTypes(false),
                null
            };

            ChildInBaseList = new List<SimpleTypes>() {
                new SimpleTypesChild(init),
                null,
                new SimpleTypesChild(false),
                null
            };

            MixedList = new List<object>() {
                new SimpleTypesChild(init),
                new SimpleTypesChild(false),
                null,
                new SimpleTypes(init),
                new SimpleTypesChild(false),
                new SimpleTypes(false),
                null
            };
            #endregion

            #region array
            ChildArray = new [] {
                new SimpleTypesChild(init),
                null,
                new SimpleTypesChild(false),
                null
            };

            BaseArray = new [] {
                new SimpleTypes(init),
                null,
                new SimpleTypes(false),
                null
            };

            ChildInBaseArray = new [] {
                new SimpleTypesChild(init),
                null,
                new SimpleTypesChild(false),
                null
            };

            MixedArray = new[] {
                new SimpleTypesChild(init),
                new SimpleTypesChild(false),
                null,
                new SimpleTypes(init),
                new SimpleTypesChild(false),
                new SimpleTypes(false),
                null
            };
            #endregion

            #region dictionaries
            ChildDict = new Dictionary<string, SimpleTypesChild>()
            {
                { "item 1", new SimpleTypesChild(init) },
                { "item 2", null },
                { "item 3", new SimpleTypesChild(false) },
                { "item 4", null }
            };

            BaseDict = new Dictionary<Guid, SimpleTypes>()
            {
                { Guid.NewGuid(), new SimpleTypes(init) },
                { Guid.NewGuid(), null },
                { Guid.NewGuid(), new SimpleTypes(false) },
                { Guid.NewGuid(), null }
            };

            ChildInBaseDict = new Dictionary<int, SimpleTypes>() {
                {1, new SimpleTypesChild(init)},
                {2, null},
                {3, new SimpleTypesChild(false)},
                {4, null}
            };
            
            MixedDict = new Dictionary<string, object>()
            {
                { "mixed item 1", new SimpleTypesChild(init) },
                { "mixed item 2", new SimpleTypesChild(false) },
                { "mixed item 3", null },
                { "mixed item 4", new SimpleTypes(init) },
                { "mixed item 5", new SimpleTypesChild(false) },
                { "mixed item 6", new SimpleTypes(false) },
                { "mixed item 7", null },
            };
            #endregion
        }

        int IComparable.CompareTo(object o)
        {
            var r = (MixedBaseChild) o;

            var errors = 0;
            if (ObjectCollections.compare(Child, r.Child)!=0) errors++;
            if (ObjectCollections.compare(Base, r.Base)!=0) errors++;
            if (ObjectCollections.compare(ChildInBaseField, r.ChildInBaseField)!=0) errors++;
            
            if (ObjectCollections.compare(ChildList, r.ChildList) != 0) errors++;
            if (ObjectCollections.compare(BaseList, r.BaseList) != 0) errors++;
            if (ObjectCollections.compare(ChildInBaseList, r.ChildInBaseList) != 0) errors++;
            if (ObjectCollections.compare(MixedList, r.MixedList) != 0) errors++;

            if (ObjectCollections.compare(ChildArray, r.ChildArray) != 0) errors++;
            if (ObjectCollections.compare(BaseArray, r.BaseArray) != 0) errors++;
            if (ObjectCollections.compare(ChildInBaseArray, r.ChildInBaseArray) != 0) errors++;
            if (ObjectCollections.compare(MixedArray, r.MixedArray) != 0) errors++;

            var eq = new ObjectCollectionEqualityComparer();

            if (!((ChildDict == null && r.ChildDict == null) || (ChildDict.Keys.SequenceEqual(r.ChildDict.Keys, eq) && ChildDict.Keys.All(p => ObjectCollections.compare(r.ChildDict[p], ChildDict[p]) == 0)))) errors++;
            if (!((BaseDict == null && r.BaseDict == null) || (BaseDict.Keys.SequenceEqual(r.BaseDict.Keys) && BaseDict.Keys.All(p => ObjectCollections.compare(r.BaseDict[p], BaseDict[p]) == 0)))) errors++;
            if (!((ChildInBaseDict == null && r.ChildInBaseDict == null) || (ChildInBaseDict.Keys.SequenceEqual(r.ChildInBaseDict.Keys) && ChildInBaseDict.Keys.All(p => ObjectCollections.compare(r.ChildInBaseDict[p], ChildInBaseDict[p]) == 0)))) errors++;
            if (!((MixedDict == null && r.MixedDict == null) || (MixedDict.Keys.SequenceEqual(r.MixedDict.Keys) && MixedDict.Keys.All(p => ObjectCollections.compare(r.MixedDict[p], MixedDict[p]) == 0)))) errors++;

            return errors == 0 ? 0 : 1;
        }
    }
}